import React from 'react';
import { Button, Col, Row, Space, message, Modal, Form, Select } from 'antd';
import UsersInfo from './components/UsersInfo';
import ProgressRecord from './components/ProgressRecord';

import './style.scss';
import { CallTaskInfoMsg, DiaogueMsg } from 'seats/schema/SocketMessage';
import { ChatMessage } from 'seats/schema/ChatSeat';
import { ManListenCall, ManListenCallSession, TaskInfo } from 'seats/schema/Task';
import {
  robotsSkipnodes,
  tasksSkip,
  tasksHangup,
  tasksReturn,
} from 'seats/servers/modules/CheckInOut';
import { FlowNodesScama } from 'seats/schema/CheckInOut';
import CallTime from 'seats/components/CallTime';
import { Chat } from 'components/Chat';
import eventBus from 'utils/eventBus';
import { JSONObject } from '../../../schema/common';

import { connect } from 'react-redux';
import { renderExceptionDom } from '../TaskTool';
import { webDebug } from 'utils/tools';

const { Option } = Select;

interface IStates {
  /**模块页面数据 */
  callInfo: ManListenCall;
  /**当前展示的聊天数据记录（根据弹屏数，最多5组） */
  currentRecord: ManListenCallSession[];
  /**右上方操作loading（网速慢，禁止其他操作） */
  headerLoading: boolean;
  /**跳转节点弹窗 */
  isModalVisible: boolean;
  /**流程节点列表 */
  flowNodes: FlowNodesScama[];
  /**接听是否挂断 */
  isRingStop: boolean;
}

interface IProps {
  /**任务详情 */
  taskInfo: TaskInfo;
  /**弹屏数 */
  screenNum: number;
  /**坐席小休开关，on-开启，off-取消 */
  seatRest: 'on' | 'off';
  /**录音模版Id */
  soundTemplateId: '';
  /**是否显示人机交互弹窗 */
  showHumanDialog: boolean;
  /**人机交互类型 robot == 转人工接听， seat == 人工介入 */
  type: string;
  /**callRecordId */
  callRecordId: string;
  /**centerCallId */
  centerCallId: string;
  /**父组件事件 关闭人机交互组件 */
  onHideHmDialog: (type?: string) => void;
  /**history对象 */
  history: any;
}
/**人机交互页面
 * 来源：人工介入
 * 来源：转人工组件
 */
class HumanIntervention extends React.Component<IProps, IStates> {
  /**
   * 回话记录控件的引用集
   */
  private chatRef: React.RefObject<any>;

  /**
   * 对话推送消息
   */
  private chatProgressRecord: DiaogueMsg;

  /**
   * 聊天缓存
   * 在实际业务中，可能会同时有很多呼叫/通话，但是界面上只有两个聊天回话窗口，
   * 记录一个缓存将收到的但是不能渲染到界面的会话消息保存起来，已保证切换聊天窗口后信息的完整度
   */
  private chatCache: Map<string, ChatMessage[]> = new Map();

  /**
   * 跳转节点ref
   */
  private formRef: React.RefObject<any>;

  constructor(props: IProps) {
    super(props);

    // 初始化设置弹屏box窗口
    this.chatRef = React.createRef();
    this.formRef = React.createRef();
    this.chatProgressRecord = {} as DiaogueMsg;
    this.state = {
      callInfo: {} as CallTaskInfoMsg,
      currentRecord: [],
      headerLoading: false,
      isModalVisible: false,
      flowNodes: [],
      isRingStop: false,
    };

    this.goJieDian = this.goJieDian.bind(this);
    this.showModal = this.showModal.bind(this);
    this.handleOk = this.handleOk.bind(this);
    this.zhlcFn = this.zhlcFn.bind(this);
    this.ringStopClick = this.ringStopClick.bind(this);
    this.handleCancel = this.handleCancel.bind(this);
    this.getRobotsSkipnodes = this.getRobotsSkipnodes.bind(this);
    this.hideHmDialog = this.hideHmDialog.bind(this);
  }

  componentDidMount() {
    this.getRobotsSkipnodes();
    // 通话被挂机
    eventBus.on('ended', (flag: string) => {
      // 人工介入弹窗-显示状态
      if (!this.props.showHumanDialog) {
        return;
      }
      // 判断是监听被挂断，该页面不做处理
      console.log('+++++++++++++++++++++收到ended消息+++++++++++++++++++++', flag);
      const { type } = this.props;
      if (flag === 'transfer' && type === 'robot') {
        // 停止振铃
        this.setState({
          isRingStop: true,
        });
        console.log(flag, type, `挂断【转人工接听】&&&&&&&--ok`);
      }
      if (flag === 'intercept' || flag === 'seat') {
        // 停止振铃
        this.setState({
          isRingStop: true,
        });
        console.log(flag, type, `挂断【人工介入】&&&&&&&--ok`);
      }
    });
  }

  componentDidUpdate(prevProps: Readonly<any>, prevState: Readonly<IStates>, snapshot?: any): void {
    const { callRecordId, showHumanDialog } = this.props;
    if (prevProps.callRecordId !== callRecordId) {
      this.getRobotsSkipnodes(); //获取节点列表
    }
    if (prevProps.showHumanDialog !== showHumanDialog && !showHumanDialog) {
      this.setState({
        isRingStop: false,
      });
    }
  }

  componentWillUnmount = () => {
    eventBus.remove('ended');
    this.setState = () => {
      return;
    };
  };

  /**
   * 获取节点列表
   */
  async getRobotsSkipnodes() {
    const { robotId } = this.props.taskInfo as TaskInfo;
    if (!robotId) return false;
    const result = await robotsSkipnodes(robotId);
    if (result.data) {
      this.setState({
        flowNodes: result.data,
      });
    }
  }

  /**
   * 接收task推送消息
   */
  onReceiveTaskStatusMsg(data: any) {
    // 任务Id
    const currentId = (this.props.taskInfo as TaskInfo).taskId;
    // 查找当前任务id对应的socket信息
    if (data.taskId !== currentId?.toString()) {
      return;
    }
    // 存储当前任务的推送信息
    const sessions = (data.sessions || []).filter(
      (item: any) => item.callRecordId === this.props.callRecordId
    );
    if (!sessions.length) {
      return;
    }
    console.log('==【人工弹窗】===onReceive====', data);
    this.setState({
      callInfo: data as CallTaskInfoMsg,
      currentRecord: [...sessions],
    });
  }

  /**
   * 收到会话的socket消息后，将数据处理一遍格式，转为Chat组件接受的数据格式，渲染会话消息并记录到缓存中
   */
  onReceiveMsg(data: DiaogueMsg) {
    // 缓存聊天信息
    const cache = this.chatCache;
    const callRecordId = (data as DiaogueMsg).callRecordId;
    const record = cache.get(callRecordId) || [];

    const speakerMap = {
      '0': 'called',
      '1': 'caller',
      '2': 'man',
    };
    record.push({
      index: data.index,
      role: speakerMap[data.speaker as '0' | '1' | '2'] as 'called' | 'caller' | 'man',
      message: data.content,
      sound: data.url,
      status: data.status,
    });

    // 根据callRecordId，存储会话记录
    cache.set(callRecordId, record);
    this.showOnScreenBox(callRecordId, record);
    //流程记录
    this.chatProgressRecord = data;
  }

  /**数据上屏展示 */
  private showOnScreenBox(callRecordId: string, record: any) {
    // 目标元素：根据callRecordId在聊天记录中查找过滤
    if (this.chatRef.current?.getCallRecordId() === callRecordId) {
      this.chatRef.current?.setRecord(record);
    }
  }

  /**
   * 根据callRecordId获得一段对话
   */
  private getChatMsg(callRecordId: string): ChatMessage[] {
    return this.chatCache.get(callRecordId) || [];
  }

  /**
   * Chat组件点击查看历史后，将历史会话信息填入缓存中
   */
  private onGetHistory(msg: ChatMessage[], callRecordId: string): void {
    this.chatCache.set(callRecordId, msg);
    this.showOnScreenBox(callRecordId, msg);
  }

  /**
   * 点击显示节点弹窗
   */
  goJieDian() {
    this.showModal();
  }

  /**
   * 显示节点弹窗
   */
  showModal() {
    this.setIsModalVisible(true);
  }

  /**
   * 隐藏节点弹窗
   */
  handleCancel() {
    this.setIsModalVisible(false);
  }

  /**
   * 设置显示与隐藏节点弹窗
   */
  setIsModalVisible(tag: boolean) {
    this.setState({
      isModalVisible: tag,
    });
  }

  /**
   * 跳转节点弹窗 点击确定
   */
  handleOk = async () => {
    try {
      const values = await this.formRef.current.validateFields();
      const { centerCallId } = this.props;
      console.log(centerCallId, '即将跳转节点***', values);
      if (centerCallId) {
        const result = await tasksSkip(centerCallId, values.nodeId);
        if (result.code === 0) {
          message.success('跳转节点成功', 1);
          this.hideHmDialog();
        }
      } else {
        console.error('错误：人机交互centerCallId不存在，无法跳转');
      }
    } catch (error) {
      console.error(`系统异常: ${JSON.stringify(error)}`);
    }
  };

  /**
   * 点击挂机
   */
  async ringStopClick() {
    const { centerCallId } = this.props;
    console.log(`挂机centerCallId----${centerCallId}`);
    if (!centerCallId) return;
    const result = await tasksHangup(centerCallId);
    if (result.code === 0) {
      message.success('挂断成功', 1);
      this.setState({
        isRingStop: true,
      });
    }
  }

  /**
   * 转回流程
   */
  async zhlcFn() {
    const { centerCallId } = this.props;
    console.log(`跳转节点centerCallId----${centerCallId}`);
    if (!centerCallId) return;
    const result = await tasksReturn(centerCallId);
    if (result.code === 0) {
      message.success('转回流程成功', 1);
      this.hideHmDialog();
    }
  }

  /**
   * 隐藏人机交互弹窗
   */
  hideHmDialog(messageMsg?: string) {
    // (this.props as JSONObject).setScreenNum(1);
    // (this.props as JSONObject).setSeatRest('off');

    // 每次都重新存取数据，避免在弹窗关闭时，存在数据丢失
    const { callRecordId } = this.props;
    this.chatCache.set(callRecordId, []);

    this.setState({
      callInfo: {} as CallTaskInfoMsg,
      currentRecord: [],
      headerLoading: false,
      isModalVisible: false,
      flowNodes: [],
      isRingStop: false,
    });

    this.props.onHideHmDialog(messageMsg);
  }

  /**
   * 点击返回 按钮
   */
  goBackToList = () => {
    this.hideHmDialog();
  };

  render() {
    const { callInfo, currentRecord, isRingStop } = this.state;
    const { seatRest, centerCallId, callRecordId, type, showHumanDialog } = this.props;
    const curItem = currentRecord.find(item => item.callRecordId === callRecordId);
    if (!showHumanDialog) return null;
    return (
      <div className="common-full-page human-intervention-page human-intervention-page-fixed">
        <div className="header">
          <Row justify="end">
            <Col flex="auto" className="title">
              <span style={{ fontSize: 16, fontWeight: 'bold' }}>
                {type === 'robot' ? '转人工' : '人工介入'}
              </span>
              {webDebug && (
                <span>
                  <b className="debug-style">【呼叫中心Id：{centerCallId}】</b>
                  <em>【流水号：{callRecordId}】</em>
                </span>
              )}
            </Col>
            <Col flex="300px" className="top-right-btn-box">
              {/* 坐席挂断或者呼叫用户挂断，显示【返回】按钮 */}
              {isRingStop ? (
                <Space>
                  <Button type="primary" ghost onClick={this.goBackToList}>
                    返回
                  </Button>
                </Space>
              ) : (
                <Space>
                  <span>
                    {!!callInfo && currentRecord.length > 0 && curItem && (
                      <CallTime beginTime={curItem.inviteTime} />
                    )}
                  </span>
                  <Button type="primary" style={{ marginRight: 8 }} onClick={this.ringStopClick}>
                    挂断
                  </Button>
                  {type === 'robot' && (
                    <Button type="primary" ghost onClick={this.zhlcFn}>
                      转回流程
                    </Button>
                  )}
                  <Button type="primary" ghost onClick={this.goJieDian}>
                    跳转节点
                  </Button>
                  <Modal
                    title="请选择跳转节点"
                    visible={this.state.isModalVisible}
                    onOk={this.handleOk}
                    onCancel={this.handleCancel}
                  >
                    <Form name="control-hooks" ref={this.formRef}>
                      <Form.Item
                        label="跳转节点"
                        name="nodeId"
                        rules={[{ required: true, message: '请选择跳转节点' }]}
                      >
                        <Select placeholder="请选择跳转节点">
                          {this.state.flowNodes.map(item => {
                            return (
                              <Option key={item.id} value={item.id}>
                                {item.title}
                              </Option>
                            );
                          })}
                        </Select>
                      </Form.Item>
                    </Form>
                  </Modal>
                </Space>
              )}
            </Col>
          </Row>
        </div>
        <div className="body">
          <Row className="box-row">
            <Col className="box" flex="2 2 0">
              <UsersInfo callRecordId={callRecordId} />
            </Col>
            <Col className="box" flex="2 2 0">
              <div className="box-cont max-height">
                <div className="box-tit">流程记录</div>
                <ProgressRecord
                  callRecordId={callRecordId}
                  chatProgressRecord={this.chatProgressRecord}
                />
              </div>
            </Col>
            <Col className="box" flex="3 3 0">
              <div className="box-cont max-height">
                <div className="box-tit">通话记录</div>
                {!!callInfo && currentRecord.length > 0 && (
                  <>
                    {currentRecord.map((chatInfo, index) => (
                      // 通话记录-循环展示
                      // 此处实际场景，只有一个对话记录展示
                      <div className="box-cont no-padding" key={chatInfo.callRecordId}>
                        {/* 接通,有会话内容则显示 */}
                        {!!chatInfo && (
                          <Chat
                            showStatusHeader={false}
                            showHistoryLink={true}
                            key={chatInfo.callId}
                            ref={this.chatRef}
                            callSerialNumber={chatInfo.callSerialNumber}
                            callRecordId={chatInfo.callRecordId}
                            centerCallId={chatInfo.callId}
                            phoneNum={chatInfo.number}
                            status={chatInfo.state}
                            messages={this.getChatMsg(chatInfo.callRecordId)}
                            onGetHistory={this.onGetHistory.bind(this)}
                          />
                        )}
                        {/* 无通话内容 */}
                        {!chatInfo && renderExceptionDom(callInfo, seatRest)}
                      </div>
                    ))}
                  </>
                )}
              </div>
            </Col>
          </Row>
        </div>
      </div>
    );
  }
}

// state 注入props
const mapStateToProps = (state: JSONObject) => {
  return {
    taskInfo: state.workspaceInfo,
    seatRest: state.seatRest,
    screenNum: state.screenNum,
    soundTemplateId: state.soundTemplateId,
  };
};
// action 注入props
const mapDispatchToProps = {};

export default connect(mapStateToProps, mapDispatchToProps, null, { forwardRef: true })(
  // @ts-ignore
  HumanIntervention
);
